import { Vec3 } from 'cc';

/**
 * GameEventMap: 游戏内事件与其载荷类型映射。
 * 该类型会被 on/off/emit 的泛型约束复用，以提供端到端的类型安全。
 */
export interface GameEventMap {
  'match/start': { seed: number; map: string };
  'match/end': { result: 'extract' | 'death' | 'quit' };
  'entity/spawn': { id: string; kind: 'player' | 'enemy' | 'projectile' };
  'entity/die': { id: string; killer?: string };
  'combat/hit': { src: string; dst: string; dmg: number; isCrit: boolean; pierceLeft: number };
  'ammo/changed': { weaponId: string; mag: number; reserve: number };
  'ammo/out': { weaponId: string };
  'reload/begin': { weaponId: string; t: number };
  'reload/end': { weaponId: string };
  'weapon/switch': { slot: 'primary' | 'secondary'; weaponId: string };
  'hud/toast': { text: string; ms: number };
  'extract/available': { at: Vec3 };
  'input/move': { x: number; y: number };
}

type Handler<K extends keyof GameEventMap> = (payload: GameEventMap[K]) => void;

/** 基于 Map<string, Set<Function>> 的轻量事件总线。 */
export class EventBus {
  private listeners: Map<keyof GameEventMap, Set<Function>> = new Map();

  on<K extends keyof GameEventMap>(event: K, handler: Handler<K>): () => void {
    const set = this.listeners.get(event) ?? new Set<Function>();
    set.add(handler as Function);
    this.listeners.set(event, set);
    return () => this.off(event, handler);
  }

  off<K extends keyof GameEventMap>(event: K, handler: Handler<K>): void {
    const set = this.listeners.get(event);
    if (!set) {
      return;
    }
    set.delete(handler as Function);
    if (set.size === 0) {
      this.listeners.delete(event);
    }
  }

  emit<K extends keyof GameEventMap>(event: K, payload: GameEventMap[K]): void {
    const set = this.listeners.get(event);
    if (!set) {
      return;
    }
    for (const fn of Array.from(set)) {
      (fn as Handler<K>)(payload);
    }
  }

  clear(): void {
    this.listeners.clear();
  }
}

export const GlobalEventBus = new EventBus();

// Top-level helpers as required by spec
export function on<K extends keyof GameEventMap>(type: K, handler: Handler<K>): () => void {
  return GlobalEventBus.on(type, handler);
}

export function off<K extends keyof GameEventMap>(type: K, handler: Handler<K>): void {
  GlobalEventBus.off(type, handler);
}

export function emit<K extends keyof GameEventMap>(type: K, payload: GameEventMap[K]): void {
  if (typeof console !== 'undefined' && console.debug) {
    try {
      // Minimal log to aid debugging while staying lightweight
      console.debug('[EVT]', String(type), payload ?? {});
    } catch {}
  }
  GlobalEventBus.emit(type, payload);
}

// Default export to ease testing imports
export default {
  on,
  off,
  emit,
  bus: GlobalEventBus,
};
